package com.dtp.common.em;

import com.dtp.common.ex.DtpException;
import com.dtp.common.queue.MemorySafeLinkedBlockingQueue;
import com.dtp.common.queue.VariableLinkedBlockingQueue;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;

import static com.dtp.common.constant.DynamicTpConst.M_1;

/**
 * 队列类型
 *
 * @author yanhom
 * @since 1.0.0
 *
 * @remark muse
 **/
@Slf4j
@Getter
public enum QueueTypeEnum {

    /** 阻塞队列类型 */
    ARRAY_BLOCKING_QUEUE(1, "ArrayBlockingQueue"),
    LINKED_BLOCKING_QUEUE(2, "LinkedBlockingQueue"),
    PRIORITY_BLOCKING_QUEUE(3, "PriorityBlockingQueue"),
    DELAY_QUEUE(4, "DelayQueue"),
    SYNCHRONOUS_QUEUE(5, "SynchronousQueue"),
    LINKED_TRANSFER_QUEUE(6, "LinkedTransferQueue"),
    LINKED_BLOCKING_DEQUE(7, "LinkedBlockingDeque"),
    VARIABLE_LINKED_BLOCKING_QUEUE(8, "VariableLinkedBlockingQueue"),
    MEMORY_SAFE_LINKED_BLOCKING_QUEUE(9, "MemorySafeLinkedBlockingQueue");

    private final Integer code; // 编码
    private final String name;  // 名称

    QueueTypeEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }

    /** 构建阻塞队列 */
    public static BlockingQueue<Runnable> buildLbq(String name, int capacity) {
        return buildLbq(name, capacity, false, 256);
    }

    /** 根据name值，构建相应的阻塞队列实例对象 */
    public static BlockingQueue<Runnable> buildLbq(String name, int capacity, boolean fair, int maxFreeMemory) {
        BlockingQueue<Runnable> blockingQueue = null;
        if (Objects.equals(name, ARRAY_BLOCKING_QUEUE.getName()))
            blockingQueue = new ArrayBlockingQueue<>(capacity);
        else if (Objects.equals(name, LINKED_BLOCKING_QUEUE.getName()))
            blockingQueue = new LinkedBlockingQueue<>(capacity);
        else if (Objects.equals(name, PRIORITY_BLOCKING_QUEUE.getName()))
            blockingQueue = new PriorityBlockingQueue<>(capacity);
        else if (Objects.equals(name, DELAY_QUEUE.getName()))
            blockingQueue = new DelayQueue();
        else if (Objects.equals(name, SYNCHRONOUS_QUEUE.getName()))
            blockingQueue = new SynchronousQueue<>(fair);
        else if (Objects.equals(name, LINKED_TRANSFER_QUEUE.getName()))
            blockingQueue = new LinkedTransferQueue<>();
        else if (Objects.equals(name, LINKED_BLOCKING_DEQUE.getName()))
            blockingQueue = new LinkedBlockingDeque<>(capacity);
        else if (Objects.equals(name, VARIABLE_LINKED_BLOCKING_QUEUE.getName()))
            blockingQueue = new VariableLinkedBlockingQueue<>(capacity);
        else if (Objects.equals(name, MEMORY_SAFE_LINKED_BLOCKING_QUEUE.getName()))
            blockingQueue = new MemorySafeLinkedBlockingQueue<>(capacity, maxFreeMemory * M_1);

        if (blockingQueue != null) return blockingQueue;

        throw new DtpException("Cannot find specified BlockingQueue " + name);
    }
}
